# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

"""Lambda 表达式测试

覆盖 Lambda 关键机制：
1. 基础功能：简单 lambda、参数、立即调用
2. 类型推导：双向类型推导、赋值目标推导、容器元素推导
3. 闭包：变量捕获、多 lambda 共享、修改检测
"""

from gtest import EXPECT_EQ, test
from typing import Callable, Any, TypeVar

# 定义 TypeVar（用于模板参数测试）
T = TypeVar("T")
R = TypeVar("R")


@test("Lambda", "SimpleLambda")
def test_simple_lambda():
    """测试简单的 lambda 表达式"""
    square = lambda x: x * x
    EXPECT_EQ(square(5), 25)
    EXPECT_EQ(square(10), 100)


@test("Lambda", "LambdaWithTwoParams")
def test_lambda_with_two_params():
    """测试双参数 lambda"""
    add = lambda x, y: x + y
    EXPECT_EQ(add(3, 4), 7)
    EXPECT_EQ(add(10, 20), 30)


@test("Lambda", "LambdaNoParams")
def test_lambda_no_params():
    """测试无参数 lambda"""
    get_value = lambda: 42
    EXPECT_EQ(get_value(), 42)


@test("Lambda", "LambdaWithDefaultParam")
def test_lambda_with_default_param():
    """测试带默认参数的 lambda"""
    multiply = lambda x, y=2: x * y
    EXPECT_EQ(multiply(5), 10)
    EXPECT_EQ(multiply(5, 3), 15)


@test("Lambda", "MutableDefaultParam")
def test_mutable_default_param():
    """测试可变默认参数（Python 经典行为：默认值只初始化一次，多次调用共享）"""
    # 测试默认列表参数
    # 暂时使用非空列表测试，避免空列表初始化的潜在问题
    append_to_list = lambda x, lst=[100]: lst + [x]

    # 第一次调用：lst = [100] -> [100, 1]
    result1 = append_to_list(1)
    EXPECT_EQ(len(result1), 2)
    EXPECT_EQ(result1[0], 100)
    EXPECT_EQ(result1[1], 1)

    # 第二次调用：lst = [100] -> [100, 2]
    # 注意：我们用 lst + [x] 而不是 lst.append(x)，所以每次返回新列表
    result2 = append_to_list(2)
    EXPECT_EQ(len(result2), 2)
    EXPECT_EQ(result2[0], 100)
    EXPECT_EQ(result2[1], 2)

    # 验证默认列表只初始化一次（所有调用共享同一个 [100]）
    EXPECT_EQ(len(result1), 2)  # result1 未被影响


@test("Lambda", "MultipleDefaultParams")
def test_multiple_default_params():
    """测试多个默认参数"""
    compute = lambda a, b=2, c=3: a + b * c

    # 使用所有默认值
    EXPECT_EQ(compute(10), 16)  # 10 + 2 * 3

    # 提供 b，使用 c 的默认值
    EXPECT_EQ(compute(10, 5), 25)  # 10 + 5 * 3

    # 提供所有参数
    EXPECT_EQ(compute(10, 5, 4), 30)  # 10 + 5 * 4


@test("Lambda", "ImmediateCall")
def test_lambda_immediate_call():
    """测试立即调用的 lambda"""
    result = (lambda x: x + 1)(5)
    EXPECT_EQ(result, 6)


@test("Lambda", "LambdaInList")
def test_lambda_in_list():
    """测试 lambda 在列表中"""
    funcs = [lambda x: x + 1, lambda x: x * 2, lambda x: x * x]

    EXPECT_EQ(funcs[0](5), 6)
    EXPECT_EQ(funcs[1](5), 10)
    EXPECT_EQ(funcs[2](5), 25)


@test("Lambda", "AssignmentTargetInference")
def test_assignment_target_inference():
    """测试赋值目标类型推导 lambda 参数"""
    # 显式注解 → lambda 参数应推导为 int, int
    add: Callable[[int, int], int] = lambda x, y: x + y
    EXPECT_EQ(add(3, 4), 7)


@test("Lambda", "FunctionParameterInference")
def test_function_parameter_inference():
    """测试函数参数签名推导 lambda"""
    # 简化：直接测试 lambda 作为参数
    f: Callable[[int], int] = lambda x: x * 2
    EXPECT_EQ(f(5), 10)


@test("Lambda", "ContainerElementInference")
def test_container_element_inference():
    """测试容器元素类型推导 lambda"""
    # 使用列表容器，验证类型推导正确
    funcs = [lambda x: x + 1, lambda x: x * 2]

    EXPECT_EQ(funcs[0](5), 6)
    EXPECT_EQ(funcs[1](5), 10)


@test("Lambda", "NestedExpectedType")
def test_nested_expected_type():
    """测试嵌套期望类型"""
    # 分别调用，验证类型推导
    processors = [lambda n: n + 1, lambda n: n * 2, lambda n: n * n]

    EXPECT_EQ(processors[0](3), 4)
    EXPECT_EQ(processors[1](3), 6)
    EXPECT_EQ(processors[2](3), 9)


@test("Lambda", "ReturnTypeMatching")
def test_return_type_matching():
    """测试返回类型匹配验证"""
    # lambda 返回类型应匹配期望
    square: Callable[[int], int] = lambda x: x * x
    result = square(7)
    EXPECT_EQ(result, 49)


@test("Lambda", "PartialInference")
def test_partial_inference():
    """测试部分推导（混合显式和推导）"""
    # 参数 x, y 从期望推导为 int
    add_mixed: Callable[[int, Any], int] = lambda x, y: x + y
    add_mixed_func = add_mixed

    result = add_mixed_func(10, 20)
    EXPECT_EQ(result, 30)


# ============================================================================
# 闭包测试
# ============================================================================


@test("Lambda", "LambdaClosure")
def test_lambda_closure():
    """测试 lambda 闭包 - 捕获外部变量"""
    n: int = 2
    multiplier = lambda x: x * n
    EXPECT_EQ(multiplier(5), 10)
    EXPECT_EQ(multiplier(10), 20)


@test("Lambda", "ClosureModifiedDetection")
def test_closure_modified_detection():
    """测试数据流分析能否检测到闭包变量被修改"""
    n: int = 10
    f = lambda: n + 1

    EXPECT_EQ(f(), 11)


@test("Lambda", "MultipleSharedDetection")
def test_multiple_shared_detection():
    """测试数据流分析能否检测到多个 lambda 共享变量"""
    counter: int = 0
    inc = lambda: counter + 1
    dec = lambda: counter - 1

    EXPECT_EQ(inc(), 1)
    EXPECT_EQ(dec(), -1)


@test("Lambda", "ImmutableClosure")
def test_immutable_closure():
    """不可变闭包变量，可以按值捕获"""
    multiplier: int = 3
    f = lambda x: x * multiplier

    # 变量未被修改，按值捕获
    result1 = f(5)  # 5 * 3 = 15
    result2 = f(10)  # 10 * 3 = 30

    EXPECT_EQ(result1, 15)
    EXPECT_EQ(result2, 30)


def make_adder(x: int):
    return lambda y: x + y


def make_adder_callable(x: int) -> Callable[[int], int]:
    return lambda y: x + y


def call_adder(f: Callable[[int], int], y, z):
    return f(f(y)) + f(z)


@test("Lambda", "LambdaReturnLambda")
def test_lambda_return_lambda():
    """测试返回 lambda 的函数"""

    add_10 = make_adder(10)
    add_20 = make_adder_callable(20)

    EXPECT_EQ(add_10(5), 15)
    EXPECT_EQ(add_20(5), 25)

    # call_adder(f, y, z) = f(f(y)) + f(z)
    # add_10(5) = 15, add_10(15) = 25, add_10(100) = 110
    # 结果: 25 + 110 = 135
    EXPECT_EQ(call_adder(add_10, 5, 100), 135)
    # add_20(5) = 25, add_20(25) = 45, add_20(100) = 120
    # 结果: 45 + 120 = 165
    EXPECT_EQ(call_adder(add_20, 5, 100), 165)


# ============================================================================
# TypeVar 模板参数测试
# ============================================================================


def identity(x: T) -> T:
    """基本模板函数：返回参数本身"""
    return x


def apply(f: Callable[[T], R], x: T) -> R:
    """Callable 模板参数：应用函数 - 核心场景"""
    return f(x)


def apply_twice(f: Callable[[T], T], x: T) -> T:
    """嵌套 Callable 调用 - 单 TypeVar"""
    return f(f(x))


@test("Lambda", "TypeVarBasicTemplate")
def test_typevar_basic_template():
    """测试基本模板函数"""
    # 测试整数
    result_int: int = identity(5)
    EXPECT_EQ(result_int, 5)

    # 测试浮点数
    result_float: float = identity(2.5)
    EXPECT_EQ(result_float, 2.5)


@test("Lambda", "TypeVarCallableTemplate")
def test_typevar_callable_template():
    """测试 Callable 模板参数 - 核心场景"""
    # 测试 int -> int
    add_1 = lambda x: x + 1
    result1: int = apply(add_1, 5)
    EXPECT_EQ(result1, 6)

    # 测试 int -> int (不同的函数)
    multiply_2 = lambda x: x * 2
    result2: int = apply(multiply_2, 5)
    EXPECT_EQ(result2, 10)


@test("Lambda", "TypeVarCallableTwice")
def test_typevar_callable_twice():
    """测试嵌套 Callable 调用"""
    add_1 = lambda x: x + 1
    result1: int = apply_twice(add_1, 5)
    # 5 + 1 = 6, 6 + 1 = 7
    EXPECT_EQ(result1, 7)

    # 测试另一个单参数 lambda
    multiply_3 = lambda x: x * 3
    result2: int = apply_twice(multiply_3, 5)
    # 5 * 3 = 15, 15 * 3 = 45
    EXPECT_EQ(result2, 45)


# ============================================================================
# 嵌套函数测试
# ============================================================================


def make_multiplier_nested(factor: int) -> Callable[[int], int]:
    def multiply(x: int) -> int:
        return x * factor

    return multiply


def make_calculator_nested(
    x: int, y: int
) -> tuple[Callable[[], int], Callable[[], int]]:
    def add() -> int:
        return x + y

    def multiply() -> int:
        return x * y

    return add, multiply


@test("NestedFunction", "BasicNested")
def test_basic_nested_function():
    """测试基本嵌套函数"""
    doubler = make_multiplier_nested(2)
    tripler = make_multiplier_nested(3)

    EXPECT_EQ(doubler(5), 10)
    EXPECT_EQ(tripler(5), 15)


@test("NestedFunction", "StackNestedFunction")
def test_stack_nested_function():
    """测试栈模式嵌套函数"""

    def multiply(x: int) -> int:
        return x * 2

    EXPECT_EQ(multiply(5), 10)
    EXPECT_EQ(multiply(10), 20)


@test("NestedFunction", "MultipleCaptures")
def test_nested_function_multiple_captures():
    """测试嵌套函数捕获多个变量"""
    add_func_1, mul_func_1 = make_calculator_nested(3, 4)
    add_func_2, mul_func_2 = make_calculator_nested(3, 4)
    EXPECT_EQ(add_func_1(), 7)
    EXPECT_EQ(mul_func_1(), 12)
    EXPECT_EQ(add_func_1(), add_func_2())
    EXPECT_EQ(mul_func_1(), mul_func_2())


@test("NestedFunction", "DefaultParameters")
def test_nested_function_default_params():
    """测试嵌套函数的默认参数（复用 Lambda 机制）"""

    def greet(name: str = "World") -> str:
        return "Hello, " + name

    # 不传参数，使用默认值
    EXPECT_EQ(greet(), "Hello, World")
    # 传参数，覆盖默认值
    EXPECT_EQ(greet("Python"), "Hello, Python")


@test("NestedFunction", "DefaultParametersWithCapture")
def test_nested_function_default_params_with_capture():
    """测试嵌套函数的默认参数 + 闭包捕获"""

    def make_greeter(prefix: str):
        def greet(name: str = "World") -> str:
            return prefix + name

        return greet

    greeter = make_greeter("Hello, ")
    EXPECT_EQ(greeter(), "Hello, World")
    EXPECT_EQ(greeter("Python"), "Hello, Python")
